package cz.cuni.amis.episodic.bayes.experiment;

import cz.cuni.amis.episodic.lisp.behan.LispTree;
import cz.cuni.amis.episodic.lisp.netcreators.NetCreator;
import cz.cuni.amis.episodic.lisp.visitor.TreeTraceVisitor;
import cz.cuni.amis.episodic.lisp.*;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;

import smile.Network;

/**
 * Base of an experiment that reads training data from LISP like file.
 * @author ik
 */
public class LispExperiment extends Experiment {
	List<? extends NetCreator> networkCreators;
	File resourceDir; // = new File("src/main/resources");
	File inputLispPlan;
	int batchSize = 6;

	/**
	 * Should the DBNs be created from training data (this can be lengthly
	 * operation if the network contains unobserved variables and EM has to be
	 * used). Or should the testing phase just use networks in the root
	 * experiment directory.
	 */
	boolean createAndLearnNetworks = true;

	/**
	 * Create networks and performs experiment using all *.xdsl files in the
	 * experiment directory.
	 */
	@Override
	public Map<String, Map<String, DescriptiveStatistics[][]>> perform() throws Exception {

		if (createAndLearnNetworks) {
			createNetworks();
		}

		networkFilenames = targetExperimentDir.list(new FilenameFilter() {

			@Override
			public boolean accept(File dir, String name) {
				return name.endsWith(".xdsl");
			}
		});

		return super.perform();
	}

	public LispExperiment(String experimentName, File targetExperimentsDir,
			File resourcesDir, String corporaName) {
		this(experimentName, targetExperimentsDir, new File(resourcesDir, corporaName));
		resourcesDir = new File(resourcesDir, experimentName);
		resourcesDir.mkdirs();
	}

	public LispExperiment(String experimentName, File targetExperimentsDir,
			File inputLispPlan) {
		super(experimentName, targetExperimentsDir);
		this.inputLispPlan = inputLispPlan;
	}
	
	public List<Network> createNetworks() throws IOException {
		List<Network> nets = new ArrayList<>();
		// create all networks
		for (NetCreator netCreator : networkCreators) {
			netCreator.setBatchSize(batchSize);
			Network net = netCreator.createAndLearnNetwork(inputLispPlan,
					targetExperimentDir, trainingDataRange);
			nets.add(net);
		}

		return nets;
	}


	protected <T> List<List<T>> split(List<T> list, int splitSize) {
		List<List<T>> splitted = new ArrayList<>();
		for (int i = 0; i < list.size(); i += splitSize) {
			if (i + splitSize < list.size()) {
				splitted.add(list.subList(i, i+splitSize));
			}
		}
		return splitted;
	}
	
}
